﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace danalyser.Interface.Forms
{
    // Контроллеры и свойства
    using danalyser.Controllers;
    using danalyser.Properties;

    /// <summary>
    /// Редактор кода
    /// </summary>
    public partial class editorForm : Form
    {
        // Файл зменен, необходимость отображения окна поиска
        private bool change, search;
        // Текущее имя файла
        private string current;
        // Номер строки
        private int line;

        /// <summary>
        /// Загрузка файла
        /// </summary>
        /// <param name="filename">имя файла</param>
        /// <param name="line">номер строки</param>
        private new void Load(string filename, int line)
        {
            current = filename;
            this.Text = string.Format("Редактор кода - {0}", filename);
            codeBox.Text = File.ReadAllText(filename, Encoding.Default);
            if (line != 0)
                codeBox.Select(codeBox.GetFirstCharIndexFromLine(line - 1), codeBox.Lines[line - 1].Length);
            else
                codeBox.Select(0, 0);
            codeBox.Focus();
            codeBox.ScrollToCaret();
            codeBox.Refresh();
            codeBox_MouseCaptureChanged(this, new EventArgs());
            change = false;
        }

        /// <summary>
        /// Сохранение файла
        /// </summary>
        /// <param name="filename">имя файла</param>
        private void Save(string filename)
        {
            try
            {
                current = filename;
                FileAttributes OldAttributes = File.GetAttributes(filename), NewAttibutes = OldAttributes;
                bool readOnly, hidden;
                if (readOnly = ((OldAttributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly))
                    NewAttibutes ^= FileAttributes.ReadOnly;
                if (hidden = ((OldAttributes & FileAttributes.Hidden) == FileAttributes.Hidden))
                    NewAttibutes ^= FileAttributes.Hidden;
                if (readOnly || hidden) File.SetAttributes(filename, NewAttibutes);
                File.WriteAllText(filename, codeBox.Text, Encoding.Default);
                if (readOnly)
                    File.SetAttributes(filename, OldAttributes);
                change = false;
            }
            catch (Exception)
            {
                switch (MessageBox.Show("Во время сохранения произошла ошибка!\nВозможно файл защищен от записи.", "Внимание!", MessageBoxButtons.RetryCancel, MessageBoxIcon.Warning))
                {
                    case DialogResult.Retry:
                        Save(filename);
                        break;
                }
            }
        }

        /// <summary>
        /// Проверка, может ли файл быть закрыт (если надо, будет сохранен)
        /// </summary>
        /// <returns>результат</returns>
        private bool IsSaved()
        {
            if (change)
            {
                switch (MessageBox.Show("Данные в справочнике были изменены.\nСохранить изменения?", "Внимание", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
                {
                    case DialogResult.Cancel:
                        return false;
                    case DialogResult.Yes:
                        сохранитьToolStripMenuItem_Click(this, new EventArgs());
                        if (change) return false;
                        break;
                }
                return true;
            }
            else return true;
        }

        /// <summary>
        /// Активация меню
        /// </summary>
        private void EnableMenu()
        {
            bool canexecute = (Settings.Default.OpenWithExecutable != "");
            string temptext = (canexecute) ? Path.GetFileName(Settings.Default.OpenWithExecutable) : "...";
            открытьСПомощьюToolStripMenuItem1.Text = string.Format("Открыть с помощью {0}", temptext);
        }

        public editorForm()
        {
            InitializeComponent();
            переносПоСловамToolStripMenuItem.Checked = codeBox.WordWrap;
            current = string.Empty;
            change = search = false;
        }

        /// <summary>
        /// Отображение окна поиска, если надо
        /// </summary>
        public void NeedSearch()
        {
            if (search)
                FormController.Instance.Search.Show();
        }

        /// <summary>
        /// Скрытие окна с запоминанием состояния поиска
        /// </summary>
        /// <param name="hide"></param>
        private void ShowMe(bool hide)
        {
            if (hide)
            {
                search = FormController.Instance.Search.Visible;
                FormController.Instance.Search.Hide();
                Hide();
            }
        }

        /// <summary>
        /// Установка подсказки
        /// </summary>
        /// <param name="Hint">подсказка</param>
        private void SetHint(string Hint)
        {
            //hintLbl.Text = string.Format("Рекомендации по устранению ошибки:\r\n {0}", (Hint == string.Empty) ? "(нет)" : Hint);
            DetailBox.Text = Hint;
        }

        /// <summary>
        /// Отображение редактора с загрженным файлом
        /// </summary>
        /// <param name="FileName">имя файла</param>
        /// <param name="Line">номер строки</param>
        /// <param name="Hint">рекомендация по устранению ошибки</param>
        /// <param name="CanOpenNext">можно ли открыть следующую ошибку</param>
        public void ShowLoad(string filename, int line, string Hint, bool CanOpenNext)
        {
            SetHint(Hint);
            tabs.SelectedTab = editTab;
            current = filename;
            this.line = line;
            if (!Visible)
                Show();
            NeedSearch();
            editorForm_Shown(this, new EventArgs());
            следующаяОшибкаToolStripMenuItem.Enabled = CanOpenNext;
            предыдущаяОшибкаToolStripMenuItem.Enabled = CanOpenNext;
        }

        /// <summary>
        /// Отображение редактора с загрженным файлом
        /// </summary>
        /// <param name="FileName">имя файла</param>
        public void ShowLoad(string FileName)
        {
            ShowLoad(FileName, 0, string.Empty, false);
        }

        /// <summary>
        /// Отображение редактора пустым
        /// </summary>
        public void ShowClear()
        {
            if (!Visible)
                ShowLoad(string.Empty);
/*
            {
                SetHint(string.Empty);
                current = string.Empty;
                codeBox.Text = string.Empty;
                change = false;
                this.Text = "Редактор кода";
                Show();
                NeedSearch();
            }
*/
        }

        /// <summary>
        /// Открытие файла
        /// </summary>
        private void открытьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            openFile.FileName = "";
            if (openFile.ShowDialog() != DialogResult.Cancel)
                Load(openFile.FileName, 0);
        }

        /// <summary>
        /// Сохранение файла
        /// </summary>
        private void сохранитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (current == string.Empty)
                сохранитьКакToolStripMenuItem_Click(sender, e);
            else
                Save(current);
        }

        /// <summary>
        /// Сохранение файла как...
        /// </summary>
        private void сохранитьКакToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveFile.FileName = "";
            if (saveFile.ShowDialog() != DialogResult.Cancel)
            {
                Save(saveFile.FileName);
                this.Text = string.Format("Редактор кода - {0}", new FileInfo(saveFile.FileName).Name);
            }
        }

        /// <summary>
        /// Открытие файла с помощью сторонней программы
        /// </summary>
        /// <param name="filename">имя файла</param>
        public void OpenWith(string filename)
        {
            try
            {
                if (File.Exists(Settings.Default.OpenWithExecutable))
                {
                    System.Diagnostics.Process Executable = new System.Diagnostics.Process();
                    Executable.StartInfo.FileName = Settings.Default.OpenWithExecutable;
                    Executable.StartInfo.Arguments = Settings.Default.OpenWithCmd.Replace("%1", filename);
                    Executable.Start();
                }
                else throw new Exception();
            }
            catch (Exception)
            {
                настроитьToolStripMenuItem_Click(this, new EventArgs());
            }
        }

        /// <summary>
        /// Открытие файла с помощью внешнего редактора
        /// </summary>
        private void открытьСПомощьюToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (current == "")
                MessageBox.Show("Нечего открывать!", "Внимание", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            else OpenWith(current);
        }

        /// <summary>
        /// Настройка открытия файла с помощью внешнего редактора
        /// </summary>
        private void настроитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormController.Instance.OpenWith.ShowDialog();
            EnableMenu();
        }

        /// <summary>
        /// Выход
        /// </summary>
        private void выходToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Отмена ввода текста
        /// </summary>
        private void отменитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.Undo();
        }

        /// <summary>
        /// Вырезание текста
        /// </summary>
        private void вырезатьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.Cut();
        }

        /// <summary>
        /// Копирование текста
        /// </summary>
        private void копироватьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.Copy();
        }

        /// <summary>
        /// Вставка текста
        /// </summary>
        private void вставитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.Paste();
        }

        /// <summary>
        /// Удаление текста
        /// </summary>
        private void удалитьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.SelectedText = string.Empty;
        }

        /// <summary>
        /// Поиск в тексте
        /// </summary>
        private void найтиToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (FormController.Instance.Search.Visible)
                FormController.Instance.Search.Focus();
            else FormController.Instance.Search.Show();
        }

        /// <summary>
        /// Поиск следующего совпадения
        /// </summary>
        private void найтиДалееToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormController.Instance.Search.findBtn_Click(this, new EventArgs());
        }

        /// <summary>
        /// Выделение всего текста
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void выделитьВсеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.SelectAll();
        }

        /// <summary>
        /// Перенос по словам
        /// </summary>
        private void переносПоСловамToolStripMenuItem_Click(object sender, EventArgs e)
        {
            codeBox.WordWrap = !codeBox.WordWrap;
            переносПоСловамToolStripMenuItem.Checked = codeBox.WordWrap;
        }

        /// <summary>
        /// Отображение строки состояния
        /// </summary>
        private void строкаСостоянияToolStripMenuItem_Click(object sender, EventArgs e)
        {
            statusBar.Visible = !statusBar.Visible;
            строкаСостоянияToolStripMenuItem.Checked = statusBar.Visible;
        }

        /// <summary>
        /// Выбор шрифта
        /// </summary>
        private void шрифтToolStripMenuItem_Click(object sender, EventArgs e)
        {
            fontDlg.Font = codeBox.Font;
            if (fontDlg.ShowDialog() != DialogResult.Cancel)
                codeBox.Font = fontDlg.Font;
        }

        /// <summary>
        /// Клик по пункту меню "О программе"
        /// </summary>
        private void оПрограммеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormController.Instance.About.ShowDialog();
        }

        /// <summary>
        /// Отображение окна редактора
        /// </summary>
        private void editorForm_Shown(object sender, EventArgs e)
        {
            EnableMenu();
            строкаСостоянияToolStripMenuItem.Checked = statusBar.Visible;
            if (current != string.Empty)
                Load(current, line);
            NeedSearch();
        }

        /// <summary>
        /// Закрытие окна редактора
        /// </summary>
        private void editorForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = (e.CloseReason == CloseReason.UserClosing);
            ShowMe(e.Cancel && IsSaved());
        }

        /// <summary>
        /// Курсор переместился
        /// </summary>
        private void codeBox_MouseCaptureChanged(object sender, EventArgs e)
        {
            Status.Text = string.Format("строка: {0}", codeBox.GetLineFromCharIndex(codeBox.SelectionStart) + 1);
        }

        /// <summary>
        /// Текст изменился
        /// </summary>
        private void codeBox_TextChanged(object sender, EventArgs e)
        {
            change = true;
        }

        /// <summary>
        /// Предыдущая ошибка
        /// </summary>
        private void предыдущаяОшибкаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!FormController.Instance.Main.ShowPrevError())
            {
                предыдущаяОшибкаToolStripMenuItem.Enabled = false;
                следующаяОшибкаToolStripMenuItem.Enabled = false;
            }
        }

        /// <summary>
        /// Следующая ошибка
        /// </summary>
        private void следующаяОшибкаToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!FormController.Instance.Main.ShowNextError())
            {
                предыдущаяОшибкаToolStripMenuItem.Enabled = false;
                следующаяОшибкаToolStripMenuItem.Enabled = false;
            }
        }

        private void editorForm_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = (e.Data.GetDataPresent(DataFormats.FileDrop)) ? DragDropEffects.All : DragDropEffects.None;
        }

        private void editorForm_DragDrop(object sender, DragEventArgs e)
        {
            string[] filenames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            foreach (string filename in filenames)
                if (File.Exists(filename))
                {
                    Load(filename, 0);
                    return;
                }
        }
    }
}
